import type { Metadata } from 'next'; import Link from 'next/link'; import { notFound } from 'next/navigation'; import { DecaysByMonth, DeploymentTimeline, MembershipNote, OrbitalShells, StatusDonut } from '@/components/entities/constellation-panels'; import { Block, EventsList, ExternalLink, HeroFacts, KpiStrip, PlannedUnavailable, Tag, entityMetadata } from '@/components/entities/shared'; import { LaunchesTable, SatellitesTable, SitesTable } from '@/components/entities/tables'; import { OrbitBadge } from '@/components/ui/badges'; import { Container } from '@/components/ui/section'; import { Unavailable } from '@/components/ui/unavailable'; import { ApiError, api } from '@/lib/api'; import { fmt1, fmtDate, fmtDateTime, fmtInt, fmtPct, num, titleCase } from '@/lib/format'; import { SITE_URL, routes } from '@/lib/site'; import type { ConstellationDetail } from '@/lib/types'; type Props = { params: Promise<{ slug: string }> }; async function load(slug: string): Promise<{ d: ConstellationDetail; generatedAt: string } | null> { try { const res = await api.constellation(slug); return { d: res.data, generatedAt: res.meta.generated_at }; } catch (e) { if (e instanceof ApiError && e.notFound) return null; throw e; } } export async function generateMetadata({ params }: Props): Promise { const { slug } = await params; const r = await load(slug).catch(() => null); if (!r) return { title: 'Constellation not found', robots: { index: false } }; const { d } = r; const desc = `${d.name}${d.operator_name ? ` (${d.operator_name})` : ''}: ${fmtInt(d.active)} active satellites, ${fmtInt(d.total)} launched since ${fmtDate(d.first_launch)}. ${d.orbit_class ?? ''} ${titleCase(d.service_type)} constellation — deployment timeline, orbital shells, launch history and status.`; return entityMetadata({ title: `${d.name} — ${fmtInt(d.active)} active satellites, ${d.orbit_class ?? 'mixed'} constellation`, description: desc, path: routes.constellation(d.slug), ogImage: `${SITE_URL}${routes.constellation(d.slug)}/opengraph-image` }); } export default async function ConstellationPage({ params }: Props) { const { slug } = await params; const r = await load(slug); if (!r) notFound(); const { d, generatedAt } = r; const active = num(d.active); const planned = d.planned_count; const plannedPct = planned && active !== null ? (active / planned) * 100 : null; const jsonLd = { '@context': 'https://schema.org', '@type': 'Dataset', name: `${d.name} constellation`, description: d.description ?? `${d.name} satellite constellation tracked by SatelliteIndex`, url: `${SITE_URL}${routes.constellation(d.slug)}`, creator: d.operator_name ? { '@type': 'Organization', name: d.operator_name, url: d.operator_slug ? `${SITE_URL}${routes.operator(d.operator_slug)}` : undefined } : undefined, variableMeasured: ['active satellites', 'satellites on orbit', 'launches'], }; return (